1 /*
2 Date Input
1.2.1
3 Requires jQuery version: >=
1.2.6
4
5 Copyright (c)
2007-2008 Jonathan Leighton & Torchbox Ltd
6
7 Permission
is hereby granted, free of charge, to any person
8 obtaining a copy of
this software and associated documentation
9 files (the
"Software"), to deal in the Software without
10 restriction, including without limitation the rights to use,
11 copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the
13 Software
is furnished to do so, subject to the following
14 conditions:
15
16 The above copyright notice and
this permission notice shall be
17 included
in all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED
"AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 OTHER DEALINGS IN THE SOFTWARE.
27 */

28
29 DateInput = (function($) {
30
31 function DateInput(el, opts) {
32   
if (typeof(opts) != "object") opts = {};
33   $.extend(
this, DateInput.DEFAULT_OPTS, opts);
34   
35   
this.input = $(el);
36   
this.bindMethodsToObj("show", "hide", "hideIfClickOutside", "keydownHandler", "selectDate");
37   
38   
this.build();
39   
this.selectDate();
40   
this.hide();
41 };
42 DateInput.DEFAULT_OPTS = {
43   month_names: [
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
44   short_month_names: [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
45   short_day_names: [
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
46   start_of_week:
1
47 };
48 DateInput.prototype = {
49   build: function() {
50     
var monthNav = $('<p class="month_nav">' +
51       
'<span class="button prev" title="[Page-Up]">&#171;</span>' +
52       
' <span class="month_name"></span> ' +
53       
'<span class="button next" title="[Page-Down]">&#187;</span>' +
54       
'</p>');
55     
this.monthNameSpan = $(".month_name", monthNav);
56     $(
".prev", monthNav).click(this.bindToObj(function() { this.moveMonthBy(-1); }));
57     $(
".next", monthNav).click(this.bindToObj(function() { this.moveMonthBy(1); }));
58     
59     
var yearNav = $('<p class="year_nav">' +
60       
'<span class="button prev" title="[Ctrl+Page-Up]">&#171;</span>' +
61       
' <span class="year_name"></span> ' +
62       
'<span class="button next" title="[Ctrl+Page-Down]">&#187;</span>' +
63       
'</p>');
64     
this.yearNameSpan = $(".year_name", yearNav);
65     $(
".prev", yearNav).click(this.bindToObj(function() { this.moveMonthBy(-12); }));
66     $(
".next", yearNav).click(this.bindToObj(function() { this.moveMonthBy(12); }));
67     
68     
var nav = $('<div class="nav"></div>').append(monthNav, yearNav);
69     
70     
var tableShell = "<table><thead><tr>";
71     $(
this.adjustDays(this.short_day_names)).each(function() {
72       tableShell +=
"<th>" + this + "</th>";
73     });
74     tableShell +=
"</tr></thead><tbody></tbody></table>";
75     
76     
this.dateSelector = this.rootLayers = $('<div class="date_selector"></div>').append(nav, tableShell).insertAfter(this.input);
77     
78     
if ($.browser.msie && $.browser.version < 7) {
79       
80       
this.ieframe = $('<iframe class="date_selector_ieframe" frameborder="0" src="#"></iframe>').insertBefore(this.dateSelector);
81       
this.rootLayers = this.rootLayers.add(this.ieframe);
82       
83       $(
".button", nav).mouseover(function() { $(this).addClass("hover") });
84       $(
".button", nav).mouseout(function() { $(this).removeClass("hover") });
85     };
86     
87     
this.tbody = $("tbody", this.dateSelector);
88     
89     
this.input.change(this.bindToObj(function() { this.selectDate(); }));
90     
this.selectDate();
91   },
92
93   selectMonth: function(date) {
94     
var newMonth = new Date(date.getFullYear(), date.getMonth(), 1);
95     
96     
if (!this.currentMonth || !(this.currentMonth.getFullYear() == newMonth.getFullYear() &&
97                                 
this.currentMonth.getMonth() == newMonth.getMonth())) {
98       
99       
this.currentMonth = newMonth;
100       
101       
var rangeStart = this.rangeStart(date), rangeEnd = this.rangeEnd(date);
102       
var numDays = this.daysBetween(rangeStart, rangeEnd);
103       
var dayCells = "";
104       
105       
for (var i = 0; i <= numDays; i++) {
106         
var currentDay = new Date(rangeStart.getFullYear(), rangeStart.getMonth(), rangeStart.getDate() + i, 12, 00);
107         
108         
if (this.isFirstDayOfWeek(currentDay)) dayCells += "<tr>";
109         
110         
if (currentDay.getMonth() == date.getMonth()) {
111           dayCells +=
'<td class="selectable_day" date="' + this.dateToString(currentDay) + '">' + currentDay.getDate() + '</td>';
112         }
else {
113           dayCells +=
'<td class="unselected_month" date="' + this.dateToString(currentDay) + '">' + currentDay.getDate() + '</td>';
114         };
115         
116         
if (this.isLastDayOfWeek(currentDay)) dayCells += "</tr>";
117       };
118       
this.tbody.empty().append(dayCells);
119       
120       
this.monthNameSpan.empty().append(this.monthName(date));
121       
this.yearNameSpan.empty().append(this.currentMonth.getFullYear());
122       
123       $(
".selectable_day", this.tbody).click(this.bindToObj(function(event) {
124         
this.changeInput($(event.target).attr("date"));
125       }));
126       
127       $(
"td[date=" + this.dateToString(new Date()) + "]", this.tbody).addClass("today");
128       
129       $(
"td.selectable_day", this.tbody).mouseover(function() { $(this).addClass("hover") });
130       $(
"td.selectable_day", this.tbody).mouseout(function() { $(this).removeClass("hover") });
131     };
132     
133     $(
'.selected', this.tbody).removeClass("selected");
134     $(
'td[date=' + this.selectedDateString + ']', this.tbody).addClass("selected");
135   },
136   
137   selectDate: function(date) {
138     
if (typeof(date) == "undefined") {
139       date =
this.stringToDate(this.input.val());
140     };
141     
if (!date) date = new Date();
142     
143     
this.selectedDate = date;
144     
this.selectedDateString = this.dateToString(this.selectedDate);
145     
this.selectMonth(this.selectedDate);
146   },
147   
148   changeInput: function(dateString) {
149     
this.input.val(dateString).change();
150     
this.hide();
151   },
152   
153   show: function() {
154     
this.rootLayers.css("display", "block");
155     $([window, document.body]).click(
this.hideIfClickOutside);
156     
this.input.unbind("focus", this.show);
157     $(document.body).keydown(
this.keydownHandler);
158     
this.setPosition();
159   },
160   
161   hide: function() {
162     
this.rootLayers.css("display", "none");
163     $([window, document.body]).unbind(
"click", this.hideIfClickOutside);
164     
this.input.focus(this.show);
165     $(document.body).unbind(
"keydown", this.keydownHandler);
166   },
167   
168   hideIfClickOutside: function(
event) {
169     
if (event.target != this.input[0] && !this.insideSelector(event)) {
170       
this.hide();
171     };
172   },
173   
174   insideSelector: function(
event) {
175     
var offset = this.dateSelector.position();
176     offset.right = offset.left +
this.dateSelector.outerWidth();
177     offset.bottom = offset.top +
this.dateSelector.outerHeight();
178     
179     
return event.pageY < offset.bottom &&
180            
event.pageY > offset.top &&
181            
event.pageX < offset.right &&
182            
event.pageX > offset.left;
183   },
184   
185   keydownHandler: function(
event) {
186     
switch (event.keyCode)
187     {
188       
case 9:
189       
case 27:
190         
this.hide();
191         
return;
192       
break;
193       
case 13:
194         
this.changeInput(this.selectedDateString);
195       
break;
196       
case 33:
197         
this.moveDateMonthBy(event.ctrlKey ? -12 : -1);
198       
break;
199       
case 34:
200         
this.moveDateMonthBy(event.ctrlKey ? 12 : 1);
201       
break;
202       
case 38:
203         
this.moveDateBy(-7);
204       
break;
205       
case 40:
206         
this.moveDateBy(7);
207       
break;
208       
case 37:
209         
this.moveDateBy(-1);
210       
break;
211       
case 39:
212         
this.moveDateBy(1);
213       
break;
214       
default:
215         
return;
216     }
217     
event.preventDefault();
218   },
219   
220    stringToDate: function(
string) {
221     
var matches;
222     
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2})$/)) {
223       
return new Date(matches[1], matches[2] - 1, matches[3]);
224     }
else {
225       
return null;
226     };
227   },
228
229   
230   dateToString: function(date) {
231    
// return date.getDate() + " " + this.short_month_names[date.getMonth()] + " " + date.getFullYear();
232    
var month = (date.getMonth() + 1).toString();
233     
var dom = date.getDate().toString();
234     
if (month.length == 1) month = "0" + month;
235     
if (dom.length == 1) dom = "0" + dom;
236     
return dom + "-" + month + "-" +date.getFullYear() ;
237
238   },
239   
240   setPosition: function() {
241     
var offset = this.input.offset();
242     
this.rootLayers.css({
243       top: offset.top +
this.input.outerHeight(),
244       left: offset.left
245     });
246     
247     
if (this.ieframe) {
248       
this.ieframe.css({
249         width:
this.dateSelector.outerWidth(),
250         height:
this.dateSelector.outerHeight()
251       });
252     };
253   },
254   
255   moveDateBy: function(amount) {
256     
var newDate = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate() + amount);
257     
this.selectDate(newDate);
258   },
259   
260   moveDateMonthBy: function(amount) {
261     
var newDate = new Date(this.selectedDate.getFullYear(), this.selectedDate.getMonth() + amount, this.selectedDate.getDate());
262     
if (newDate.getMonth() == this.selectedDate.getMonth() + amount + 1) {
263       
264       newDate.setDate(
0);
265     };
266     
this.selectDate(newDate);
267   },
268   
269   moveMonthBy: function(amount) {
270     
var newMonth = new Date(this.currentMonth.getFullYear(), this.currentMonth.getMonth() + amount, this.currentMonth.getDate());
271     
this.selectMonth(newMonth);
272   },
273   
274   monthName: function(date) {
275     
return this.month_names[date.getMonth()];
276   },
277   
278   bindToObj: function(fn) {
279     
var self = this;
280     
return function() { return fn.apply(self, arguments) };
281   },
282   
283   bindMethodsToObj: function() {
284     
for (var i = 0; i < arguments.length; i++) {
285       
this[arguments[i]] = this.bindToObj(this[arguments[i]]);
286     };
287   },
288   
289   indexFor: function(array,
value) {
290     
for (var i = 0; i < array.length; i++) {
291       
if (value == array[i]) return i;
292     };
293   },
294   
295   monthNum: function(month_name) {
296     
return this.indexFor(this.month_names, month_name);
297   },
298   
299   shortMonthNum: function(month_name) {
300     
return this.indexFor(this.short_month_names, month_name);
301   },
302   
303   shortDayNum: function(day_name) {
304     
return this.indexFor(this.short_day_names, day_name);
305   },
306   
307   daysBetween: function(start, end) {
308     start = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
309     end = Date.UTC(end.getFullYear(), end.getMonth(), end.getDate());
310     
return (end - start) / 86400000;
311   },
312   
313   changeDayTo: function(dayOfWeek, date, direction) {
314     
var difference = direction * (Math.abs(date.getDay() - dayOfWeek - (direction * 7)) % 7);
315     
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + difference);
316   },
317   
318   rangeStart: function(date) {
319     
return this.changeDayTo(this.start_of_week, new Date(date.getFullYear(), date.getMonth()), -1);
320   },
321   
322   rangeEnd: function(date) {
323     
return this.changeDayTo((this.start_of_week - 1) % 7, new Date(date.getFullYear(), date.getMonth() + 1, 0), 1);
324   },
325   
326   isFirstDayOfWeek: function(date) {
327     
return date.getDay() == this.start_of_week;
328   },
329   
330   isLastDayOfWeek: function(date) {
331     
return date.getDay() == (this.start_of_week - 1) % 7;
332   },
333   
334   adjustDays: function(days) {
335     
var newDays = [];
336     
for (var i = 0; i < days.length; i++) {
337       newDays[i] = days[(i +
this.start_of_week) % 7];
338     };
339     
return newDays;
340   }
341 };
342
343 $.fn.date_input = function(opts) {
344   
return this.each(function() { new DateInput(this, opts); });
345 };
346 $.date_input = { initialize: function(opts) {
347   $(
"input.date_input").date_input(opts);
348   
349 } };

350
351 return
DateInput;
352 })(jQuery);


Gõ tìm kiếm nhanh...